package com.cetcs.kmga.dataManager.aspect;

import com.alibaba.fastjson.JSON;
import com.ccsc.auth.entity.ShiroUser;
import com.cetc.cloud.kmga.util.DateUtils;
import com.cetc.cloud.kmga.util.MqUtil;
import com.cetcs.kmga.common.BaseController;
import com.cetcs.kmga.common.BaseResponse;
import com.cetcs.kmga.dataManager.annotation.LogAnnotation;
import com.cetcs.kmga.dataManager.entity.global.FunctionMqMessage;
import com.cetcs.kmga.dataManager.entity.global.User;
import com.cetcs.kmga.dataManager.global.DataManagerConstants;
import com.cetcs.kmga.dataManager.util.BindingError;
import com.cetcs.kmga.dataManager.util.IpUtil;
import com.cetcs.kmga.dataManager.util.MqParamsUtil;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import org.apache.commons.lang.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

/**
 * @author 郭兴文
 * @version V1.0
 * @Title: 表单验证
 * @ClassName: ValidAspect.java
 * @Description: 基于AOP实现的表单验证拦截
 * @Date 2016年5月13日 上午10:00:00
 */

@Component
@Aspect
public class DataManagerAspect extends BaseController {


    //    @Around("execution(* com.cetcs.kmga.dataManager.controller.DeviceManagerController.*(..))\")  ")
    @Around("@annotation(org.springframework.web.bind.annotation.RequestMapping)")
    public Object aroundValidation(ProceedingJoinPoint pjp) throws Throwable {
        Object result;
        ShiroUser sessionUser = getSessionUser( );
//        User sessionUser = null;
        RequestMapping classRm = (RequestMapping) pjp.getSignature( ).getDeclaringType( ).getAnnotation(RequestMapping.class);
        RequestMapping methodRm = ((MethodSignature) pjp.getSignature( )).getMethod( ).getAnnotation(RequestMapping.class);

        //表单验证
        MethodSignature signature = (MethodSignature) pjp.getSignature( );
        Method method = signature.getMethod( );
        if (!BaseResponse.class.equals(method.getReturnType( )) && !"sysLogout".equals(method.getName( ))) {
            return pjp.proceed( );
        }
        Object[] args = pjp.getArgs( );
        Annotation[][] annotations = method.getParameterAnnotations( );
        for (int i = 0; i < annotations.length; i++) {
            if (!hasValidAnnotation(annotations[i])) {
                continue;
            }
            if (!(i < annotations.length - 1 && args[i + 1] instanceof BindingResult)) {
                //验证对象后面没有跟bindingResult,事实上如果没有应该到不了这一步
                continue;
            }
            BindingResult errResult = (BindingResult) args[i + 1];
            if (errResult.hasErrors( )) {
                return this.error(DataManagerConstants.FORM_VALID_FAIL, processErrors(errResult));
            }
        }

        //日志输出
        try {
            //发送MQ消息
            recordOptLog(sessionUser, pjp, 1);
            result = pjp.proceed( );
//            result = getStaticObj(pjp);
            recordOptLog(sessionUser != null ? sessionUser : null, pjp, 2);
        } catch (Exception ex) {
            recordOptLog(sessionUser, pjp, 3);
            throw new RuntimeException(ex);
        }
        return result;
    }

    private boolean hasValidAnnotation(Annotation[] annotations) {
        if (annotations == null) {
            return false;
        }
        for (Annotation annotation : annotations) {
            if (annotation instanceof Valid) {
                return true;
            }
        }
        return false;
    }

    private List<BindingError> processErrors(BindingResult result) {
        if (result != null && result.hasErrors( )) {
            List<BindingError> list = Lists.newLinkedList( );
            List<FieldError> fieldErrors = result.getFieldErrors( );
            List<String> sortFieldList = Lists.newLinkedList( );

            Object object = result.getTarget( );
            if (object != null) {
                Field[] fields = object.getClass( ).getDeclaredFields( );
                for (int j = 0; j < fields.length; j++) {
                    if (!Strings.isNullOrEmpty(fields[j].getName( ))) {
                        sortFieldList.add(fields[j].getName( ));
                    }
                }
            }

            if (sortFieldList != null && sortFieldList.size( ) > 0) {
                for (String fieldName : sortFieldList) {
                    for (int i = 0; i < fieldErrors.size( ); i++) {
                        FieldError fieldError = fieldErrors.get(i);
                        String errorFieldName = fieldError.getField( );
                        if (fieldName.equals(errorFieldName)) {
                            BindingError be = new BindingError( );
                            be.setId(fieldError.getField( ));
                            be.setMessage(fieldError.getDefaultMessage( ));
                            list.add(be);
                        }
                    }
                }
            }

            if (list.size( ) == 0) {
                for (int i = 0; i < fieldErrors.size( ); i++) {
                    FieldError fieldError = fieldErrors.get(i);
                    BindingError be = new BindingError( );
                    be.setId(fieldError.getField( ));
                    be.setMessage(fieldError.getDefaultMessage( ));
                    list.add(be);
                }
            }

            return list;
        }
        return null;
    }


    public static void recordOptLog(ShiroUser sessionUser, ProceedingJoinPoint point, int status) throws Exception {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes( )).getRequest( );
        String ip = IpUtil.getIpAddr(request);
        String result = 1 == status ? "start" : 2 == status ? "success" : 3 == status ? "failed" : "unknown";
        String methodName = point.getSignature( ).getName( );
        if (StringUtils.isNotEmpty(methodName)) {
            Class targetClass = point.getTarget( ).getClass( );
            Class[] parameterTypes = ((MethodSignature) point.getSignature( )).getMethod( ).getParameterTypes( );
            Method method = targetClass.getMethod(methodName, parameterTypes);
            boolean flag = method.isAnnotationPresent(LogAnnotation.class);
            if (flag) {
                FunctionMqMessage functionMqMessage = new FunctionMqMessage( );
                LogAnnotation logAnnotation = method.getAnnotation(LogAnnotation.class);
                String userAccount = sessionUser != null ? sessionUser.getAccount( ) : "未知";
                List<String> strings = Lists.newArrayList( );
                strings.add(ip);
                strings.add(DateUtils.format(new Date( ), DateUtils.DATE_FORMAT_2));
                strings.add(userAccount);
                strings.add(logAnnotation.module( ));
                strings.add(logAnnotation.description( ));
                strings.add(String.valueOf(logAnnotation.logType( )));
                strings.add(String.valueOf(logAnnotation.logLevel( )));
                strings.add(result);
                List<List<String>> datas = Lists.newArrayList( );
                datas.add(strings);
                functionMqMessage.setDatas(datas);
                MqUtil.getInstance(MqParamsUtil.getMqHost( ), MqParamsUtil.getMqUser( ), MqParamsUtil.getMqPwd( )).sendMessage2Queue(JSON.toJSONString(functionMqMessage), "notify_lnterface_access");

            }
        }
    }

}